#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <vector>
// 现在用RAII的思想来管理锁!
#include "lockguard.hpp"
using namespace std;

// 下面利用多线程模拟抢票
#define NUM 4

pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;

class threadData
{
public:
    threadData(int number /*, pthread_mutex_t* lock*/)
    // :_lock(lock)
    {
        _threadname = "thread-" + to_string(number);
    }

public:
    string _threadname;
    // pthread_mutex_t *_lock; //用类来包装锁
};

int tickets = 1000; // 用多线程，模拟一轮抢票

void *getTicket(void *args)
{
    // pthread_mutex_t lock; //设置了一个局部的锁,在这是设置锁是没有作用的！错误
    // 因为这样过后，每一个线程都拿到的是自己独立的锁，每个线程都有一把锁，而不是所有线程共用一把锁

    threadData *td = static_cast<threadData *>(args);
    // pthread_mutex_init(&lock, nullptr);
    const char *name = td->_threadname.c_str();
    while (true)
    {

        // pthread_mutex_lock(&lock);  //错误

        // 使用这个锁 —> 在临界区使用！ //申请锁成功，往下执行，申请失败阻塞等待
        // pthread_mutex_lock(td->_lock); //使用类包装的锁

        // 使用全局的锁:
        // pthread_mutex_lock(&g_lock);
        { //细节,好处:a 控制lock的生命周期 b 指明了临界区域
            lockguard lock(&g_lock); //RAII思想管理局部资源
            if (tickets > 0)
            {
                usleep(1000);
                printf("who=%s, get a ticket: %d\n", name, tickets); // ?
                tickets--;
                // pthread_mutex_unlock(&lock); //错误
                // pthread_mutex_unlock(td->_lock);
                //pthread_mutex_unlock(&g_lock);
            }
            else
            {
                // pthread_mutex_unlock(&lock); //错误
                // pthread_mutex_unlock(td->_lock);
                //pthread_mutex_unlock(&g_lock);
                break;
            }
        }
        usleep(13); // 模拟抢完票后的其它方式
    }
    // pthread_mutex_destroy(&lock); //销毁这个锁——错误
    printf("%s ... quit\n", name);
    return nullptr;
}

int main()
{
    pthread_mutex_t lock; // 所有线程都使用主线程栈区上的这把锁
    pthread_mutex_init(&lock, nullptr);

    vector<pthread_t> tids;
    vector<threadData *> thread_datas;
    for (int i = 1; i <= NUM; i++)
    {
        pthread_t tid;
        threadData *td = new threadData(i /*, &lock*/); // 传参传入
        pthread_create(&tid, nullptr, getTicket, td);

        tids.push_back(tid);        // 保存线程id
        thread_datas.push_back(td); // 保存new的指针
    }

    pthread_mutex_destroy(&lock); // 销毁锁

    for (auto thread : tids) // 线程等待
    {
        pthread_join(thread, nullptr);
    }
    for (auto td : thread_datas) // 销毁空间
    {
        delete td;
    }
    return 0;
}